////////////////////////////////////////////////////////////////////////////// 
//
//  cfg_cdc_ctl.v
//
//  Control interface 
//  控制接口模块。包括跨时钟采样:wr/rd的跨时钟域,产生请求信号req,包含ack触发req拉低的逻辑,包含ack的跨到cfg_ext_clk时钟域
//
//  Original Author:
//  Current Owner: 
//
////////////////////////////////////////////////////////////////////////////// 
//
// Copyright (C) 2013 Synopsys, Inc.  All rights reserved.
//
// SYNOPSYS CONFIDENTIAL - This is an unpublished, proprietary work of
// Synopsys, Inc., and is fully protected under copyright and trade secret
// laws.  You may not view, use, disclose, copy, or distribute this file or
// any information contained herein except pursuant to a valid written
// license agreement. It may not be used, reproduced, or disclosed to others
// except in accordance with the terms and conditions of that agreement.
//
////////////////////////////////////////////////////////////////////////////// 
//
//    Perforce Information
//    $Author: 
//    $File: /rtl/np_cfg_cdc_ctl.v $
//    $DateTime: 
//    $Revision: 
//
////////////////////////////////////////////////////////////////////////////// 

// `include "np_cfg_macros.v"

`timescale 1ns/10fs
module np_cfg_cdc_ctl (
// CFG External Clock and reset
input  wire          cfg_ext_clk,
input  wire          cfg_ext_clk_rst,

// Clock and reset
input  wire          cfg_clk,
input  wire          cfg_rst,

// External CFG control bus
input  wire [31:0]   cfg_ext_addr,
input  wire [31:0]   cfg_ext_wr_data,
input  wire          cfg_ext_wr_en,
input  wire          cfg_ext_rd_en,
output reg  [31:0]   cfg_ext_rd_data,
output reg           cfg_ext_ack,

input  wire          scan_mode,
input  wire          scan_set_rst,
  
// CFG control bus 
(*mark_debug = "true"*) output wire [31:0]   cfg_addr,
(*mark_debug = "true"*) output wire [31:0]   cfg_wr_data,
(*mark_debug = "true"*) output wire          cfg_wr_en,
(*mark_debug = "true"*) output wire          cfg_rd_en,
(*mark_debug = "true"*) input  wire          cfg_ack,
(*mark_debug = "true"*) input  wire [31:0]   cfg_rd_data
);

// -------------------------
// Registers and nets
// -------------------------

(*mark_debug = "true"*) wire        wr_en_pulse;
(*mark_debug = "true"*) wire        rd_en_pulse;
(*mark_debug = "true"*) wire        req_pulse;
(*mark_debug = "true"*) wire        ack_int;
reg  [31:0] addr_int;
(*mark_debug = "true"*) reg  [31:0] wr_data_int;
(*mark_debug = "true"*) reg         wr_en_int;
(*mark_debug = "true"*) reg         rd_en_int;
(*mark_debug = "true"*) reg  [31:0] rd_data_int;
(*mark_debug = "true"*) reg         rd_ack_int_d0;
(*mark_debug = "true"*) reg         wr_ack_int_d0;
(*mark_debug = "true"*) wire        rd_ack_pulse;
(*mark_debug = "true"*) wire        wr_ack_pulse;

// Mantis 7185 - Add hand-instantiated muxes on cfg_ext_addr,
// cfg_ext_wr_data, and cfg_ext_rd_data
wire [31:0] cfg_ext_addr_mux;
wire [31:0] cfg_ext_wr_data_mux;
wire [31:0] cfg_ext_rd_data_mux;

// catch a wr_en pulse
np_gen_pcatch catch_wr_en (
  .q               (wr_en_pulse),
  .rst             (cfg_rst),
  .clk             (cfg_clk),
  .scan_mode_i     (scan_mode),
  .scan_set_rst_i  (scan_set_rst),
  .d               (cfg_ext_wr_en)
);

// catch a rd_en pulse
np_gen_pcatch catch_rd_en (
  .q               (rd_en_pulse),
  .rst             (cfg_rst),
  .clk             (cfg_clk),
  .scan_mode_i     (scan_mode),
  .scan_set_rst_i  (scan_set_rst),
  .d               (cfg_ext_rd_en)
);

assign req_pulse = wr_en_pulse | rd_en_pulse;

// Mantis 7185 - Add hand-instantiated muxes on cfg_ext_addr,
// cfg_ext_wr_data, and cfg_ext_rd_data
np_gen_mux #(.WIDTH(32)) cfg_ext_addr_gen_mux (
  .out (cfg_ext_addr_mux),
  .sel (req_pulse),
  .d0  (addr_int),
  .d1  (cfg_ext_addr)
);

np_gen_mux #(.WIDTH(32)) cfg_ext_wr_data_gen_mux (
  .out (cfg_ext_wr_data_mux),
  .sel (req_pulse),
  .d0  (wr_data_int),
  .d1  (cfg_ext_wr_data)
);

always @ (posedge cfg_clk or posedge cfg_rst) begin
  if (cfg_rst) begin
    addr_int    <= 32'd0;
    wr_data_int <= 32'd0;
    wr_en_int   <= 1'b0;
    rd_en_int   <= 1'b0;
    rd_data_int <= 32'd0;
    rd_ack_int_d0 <= 1'b0;
    wr_ack_int_d0 <= 1'b0;
  end
  else begin
    addr_int    <= cfg_ext_addr_mux;    // 用req_pulse更新addr
    wr_data_int <= cfg_ext_wr_data_mux; // 用wr_en_pulse更新wr_data
    wr_en_int   <= (wr_en_pulse | wr_en_int) & ~ack_int; // 检测上升沿，用ack复位
    rd_en_int   <= (rd_en_pulse | rd_en_int) & ~ack_int; // 检测上升沿，用ack复位
    rd_data_int <= (ack_int & rd_en_int) ?  cfg_rd_data : rd_data_int; // 用ack更新读数据
    rd_ack_int_d0 <= ack_int & rd_en_int;
    wr_ack_int_d0 <= ack_int & wr_en_int;
  end
end

// Set outputs 
assign cfg_addr    = addr_int;
assign cfg_wr_data = wr_data_int;
assign cfg_wr_en   = wr_en_int;
assign cfg_rd_en   = rd_en_int;

assign ack_int = cfg_ack;

// 捕获进入到cfg_ext_clk域的读确认脉冲
np_gen_pcatch catch_rd_ack_en (
  .q               (rd_ack_pulse),
  .rst             (cfg_ext_clk_rst),
  .clk             (cfg_ext_clk),
  .scan_mode_i     (scan_mode),
  .scan_set_rst_i  (scan_set_rst),
  .d               (rd_ack_int_d0)
);

// 捕获进入到cfg_ext_clk域的写确认脉冲
np_gen_pcatch catch_wr_ack_en (
  .q               (wr_ack_pulse),
  .rst             (cfg_ext_clk_rst),
  .clk             (cfg_ext_clk),
  .scan_mode_i     (scan_mode),
  .scan_set_rst_i  (scan_set_rst),
  .d               (wr_ack_int_d0)
);

// Mantis 7185 - Add hand-instantiated muxes on cfg_ext_addr,
// cfg_ext_wr_data, and cfg_ext_rd_data
np_gen_mux #(.WIDTH(32)) cfg_ext_rd_data_gen_mux (
  .out (cfg_ext_rd_data_mux),
  .sel (rd_ack_pulse),
  .d0  (cfg_ext_rd_data),
  .d1  (rd_data_int)
);


// 触发器将数据读入cfg_ext_clk域，并为wr/rd操作产生ack
always @ (posedge cfg_ext_clk or posedge cfg_ext_clk_rst) begin
  if (cfg_ext_clk_rst) begin
    cfg_ext_rd_data <= 32'd0;
    cfg_ext_ack <= 1'b0;
  end
  else begin
    cfg_ext_rd_data <= cfg_ext_rd_data_mux;
    cfg_ext_ack <= rd_ack_pulse | wr_ack_pulse;
  end
end

endmodule

